package com.pf.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import com.pf.common.enums.JobExecuteStatusEnum;
import com.pf.dto.request.LogListReq;
import com.pf.dto.response.JobInfoResp;
import com.pf.dto.response.LogListResp;
import com.pf.enums.BaseResultEnum;
import com.pf.exception.BusinessException;
import com.pf.mapper.LogInfoMapper;
import com.pf.mapper.entity.LogInfo;
import com.pf.service.JobInfoService;
import com.pf.service.LogInfoService;
import com.pf.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author PanFei
 * @version 1.0.0
 * @createTime 2021/8/14
 */
@Slf4j
@Service
public class LogInfoServiceImpl implements LogInfoService {

    @Autowired
    private LogInfoMapper logInfoMapper;
    @Autowired
    private JobInfoService jobInfoService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertLog(LogInfo logInfo) {
        logInfo.setLogId(StringUtil.uuid());
        logInfoMapper.insert(logInfo);
    }

    @Override
    public List<LogListResp> getLogInfoList(LogListReq logReq) {
        List<JobInfoResp> jobInfos = jobInfoService.getJobInfoList(logReq);
        if (CollectionUtils.isNotEmpty(jobInfos)) {
            List<String> jobIds = jobInfos.stream().map(JobInfoResp::getJobId).distinct().collect(Collectors.toList());
            List<LogInfo> logInfos = getLogInfoByJobIds(jobIds);

            Map<String, JobInfoResp> jobInfoMap = jobInfos.stream().collect(Collectors.toMap(JobInfoResp::getJobId, Function.identity()));
            return logInfos.stream().map(logInfo -> {
                JobInfoResp jobInfoResp = jobInfoMap.get(logInfo.getJobId());
                return LogListResp.builder()
                        .jobId(logInfo.getJobId())
                        .jobName(jobInfoResp.getJobName())
                        .jobUrl(jobInfoResp.getJobUrl())
                        .jobCron(jobInfoResp.getJobCron())
                        .retryNums(jobInfoResp.getRetryNums())
                        .logId(logInfo.getLogId())
                        .executeDate(logInfo.getExecuteDate())
                        .executeStatus(logInfo.getExecuteStatus())
                        .build();
            }).collect(Collectors.toList());
        }
        return Lists.newArrayList();
    }

    @Override
    public LogListResp getLogInfo(String logId) {
        LogInfo logInfo = getLogInfoByLogId(logId);
        if (logInfo == null) {
            throw new BusinessException(BaseResultEnum.LOG_INFO_EXISTS);
        }

        JobInfoResp jobInfo = jobInfoService.getJobInfo(logInfo.getJobId());
        if (jobInfo == null) {
            throw new BusinessException(BaseResultEnum.JOB_NOT_EXISTS);
        }
        return LogListResp.builder()
                .jobId(jobInfo.getJobId())
                .jobName(jobInfo.getJobName())
                .jobUrl(jobInfo.getJobUrl())
                .jobCron(jobInfo.getJobCron())
                .retryNums(jobInfo.getRetryNums())
                .logId(logInfo.getLogId())
                .executeDate(logInfo.getExecuteDate())
                .executeStatus(logInfo.getExecuteStatus())
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateLogInfoByLogId(LogInfo logInfo) {
        Assert.notNull(logInfo, "日志信息不能为空！");
        Assert.hasText(logInfo.getLogId(), "日志id不能为空！");
        logInfoMapper.updateById(logInfo);
    }

    @Override
    public boolean isExistsRunningJob(String jobId) {
        Integer count = logInfoMapper.selectCount(new LambdaQueryWrapper<LogInfo>()
                .eq(LogInfo::getJobId, jobId)
                .eq(LogInfo::getExecuteStatus, JobExecuteStatusEnum.RUNNING.getCode())
                .eq(LogInfo::getIsDeleted, 0)
        );
        return count != null && count > 0 ? true : false;
    }


    /**
     * 通过任务id查询对应日志信息
     *
     * @param jobIds
     * @return
     */
    private List<LogInfo> getLogInfoByJobIds(List<String> jobIds) {
        return logInfoMapper.selectList(new LambdaQueryWrapper<LogInfo>()
                .in(LogInfo::getJobId, jobIds)
                .eq(LogInfo::getIsDeleted, 0)
                .orderByDesc(LogInfo::getExecuteDate)
        );
    }

    /**
     * 通过日志id查询日志信息
     *
     * @param logId
     * @return
     */
    private LogInfo getLogInfoByLogId(String logId) {
        return logInfoMapper.selectOne(new LambdaQueryWrapper<LogInfo>()
                .eq(LogInfo::getLogId, logId)
                .eq(LogInfo::getIsDeleted, 0)
        );
    }
}
